﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;


using Microsoft.Xna.Framework;
using System.IO;
using BrickBreaker;
using BrickBreaker.Core;
using System.Xml;


namespace LevelEditor
{
    public partial class Editor : Form
    {

        #region DATA_MEMBERS_PRIVATE/GLOBAL
        //Global Vars....
        public Game1 game;

        private Brick brick;
        private bool loadedAnExistingLevel = false;
        #endregion;



        public Editor()
        {
            InitializeComponent();
        }

        private void Editor_Load(object sender, EventArgs e)
        {
            //btnAddBrick.Enabled = false;
            LoadFieldsWithData();
            //LoadBrick_Textures();
            CheckEditMode_Enabled();
            
            //brick = new Brick(game.brickTexture, BrickType.BLUE, Vector2.Zero);
            //textBox_SpeedXY.Text = imageListBricks.Images.Count.ToString();
        }

        private void Editor_FormClosing(object sender, FormClosingEventArgs e)
        {
            game.Exit();
            Application.Exit();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            game.Exit();
            Application.Exit();
        }

        private void comboBoxDensity_SelectedIndexChanged(object sender, EventArgs e)
        {
            if ((BrickDensity)comboBoxDensity.SelectedIndex == BrickDensity.REGULAR)
            {
                numericUpDown_MaxHits.Enabled = true;
                numericUpDown_Score.Enabled = true;
            }
            else if ((BrickDensity)comboBoxDensity.SelectedIndex == BrickDensity.SOLID)
            {
                numericUpDown_MaxHits.Enabled = false;
                numericUpDown_MaxHits.Value = 0;

                numericUpDown_Score.Enabled = false;
                numericUpDown_Score.Value = 0;
            }

            CheckEditMode_Enabled();
        }

        private void comboBoxType_SelectedIndexChanged(object sender, EventArgs e)
        {
            pictureBoxTexture.Image = imageListBricks.Images[comboBoxType.SelectedIndex];

            CheckEditMode_Enabled();
        }

        private void numericUpDown_Score_ValueChanged(object sender, EventArgs e)
        {
            numericUpDown_Score.Value = Math.Round(numericUpDown_Score.Value / 5) * 5;
        }

        private void numericUpDown_Score_Leave(object sender, EventArgs e)
        {
            numericUpDown_Score.Value = Math.Round(numericUpDown_Score.Value / 5) * 5;
        }
        
        private void changeBGToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            BG_OnOff();
        }

        private void drawGridToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GridOnOff();
        }

        private void loadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //------------------------------------------------------------------
            if (!btnAddBrick.Enabled)
            {
                comboBoxType.SelectedIndex = 0;
                comboBoxDensity.SelectedIndex = 0;
            }

            game.unsaved = "";
            game.displayMsg = "";
            Brick temp = new Brick();

            //Clear level B4 loading new level
            //Add event hadlers to allow player to save changes to a levle b4 loading a new level
            game.bricks.Clear();
            //------------------------------------------------------------------


            OpenFileDialog loadDialog = new OpenFileDialog();

            loadDialog.Title = "Open File (Load Level)";
            loadDialog.Filter = "XML Files|*.xml";
            loadDialog.InitialDirectory = @"C:\";
            //loadDialog.InitialDirectory = @"C:\Users\Ronald\Documents\Dropbox\C#\LevelEditor\bin\x86\Debug";
            loadDialog.AddExtension = true;
            loadDialog.RestoreDirectory = false;
            //------------------------------------------------------------------
            if (loadDialog.ShowDialog() == DialogResult.OK)
            {
                string file = loadDialog.FileName;

                try
                {
                    #region READ_XML
                    XmlTextReader reader = new XmlTextReader(file); //("test.xml");

                    while (reader.Read())
                    {
                        if (reader.IsStartElement() && reader.Name == "BRICK")
                        {
                            #region ONE_NODE_AT_A_TIME
                            while (reader.Read())
                            {
                                switch (reader.Name)
                                {
                                    case "TYPE":
                                        temp.Type = (BrickType)Enum.Parse(typeof(BrickType), reader.ReadString().ToUpper());
                                        break;
                                    case "DENSITY":
                                        temp.Density = (BrickDensity)Enum.Parse(typeof(BrickDensity), reader.ReadString().ToUpper());
                                        break;
                                    case "HITCOUNT":
                                        temp.HitCount = int.Parse(reader.ReadString());
                                        break;
                                    case "SCOREVALUE":
                                        temp.ScoreValue = int.Parse(reader.ReadString());
                                        break;
                                    case "POSITION":
                                        string[] arr1 = reader.ReadString().Split();
                                        temp.Position = new Vector2(int.Parse(arr1[0]), int.Parse(arr1[1]));
                                        break;
                                    case "SIZE":
                                        string[] arr2 = reader.ReadString().Split();
                                        temp.Size = new Vector2(int.Parse(arr2[0]), int.Parse(arr2[1]));
                                        break;
                                    case "CENTER":
                                        string[] arr3 = reader.ReadString().Split();
                                        temp.Center = new Vector2(int.Parse(arr3[0]), int.Parse(arr3[1]));
                                        break;
                                    case "SPEED":
                                        string[] arr4 = reader.ReadString().Split();
                                        temp.Speed = new Vector2(int.Parse(arr4[0]), int.Parse(arr4[1]));
                                        break;
                                    case "DIRECTION":
                                        string[] arr5 = reader.ReadString().Split();
                                        temp.Direction = new Vector2(int.Parse(arr5[0]), int.Parse(arr5[1]));
                                        break;
                                }//switch
                                //One Brick Node complete
                                if (reader.Name == "BRICK" && reader.NodeType == XmlNodeType.EndElement)
                                {
                                    game.SwapBrickTexture(temp.Type);
                                    temp.Texture = game.brickTexture;
                                    game.bricks.Add(temp);
                                    temp = new Brick();
                                }
                            }//inner-while 
                            #endregion
                        }//if
                    }//outer-while
                    reader.Close();
                    #endregion

                    if (game.bricks.Count != 0)
                    {
                        //Track Level loaded, Print Msg to indicate successful load of level
                        this.loadedAnExistingLevel = true;
                        game.displayMsg = "New Level loaded into Editor";
                    }
                    else
                    {
                        this.loadedAnExistingLevel = false;
                        game.displayMsg = "File format not recognized, or does not match data structure";
                    }
                }
                catch (Exception ex)
                {
                    this.loadedAnExistingLevel = false;
                    game.displayMsg = "File format not recognized, or does not match data structure. " + ex.Message;
                }
            }
        }


        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            game.displayMsg = "";
            saveFileDialog1.ShowDialog();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LevelEditorAbout about = new LevelEditorAbout();
            about.Text = "";
            about.Show();
        }

        private void btnAddBrick_Click(object sender, EventArgs e)
        {
            AddBrickUsingTools();
  
            game.bricks.Add(brick);
        }

        private void resetAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (game.bricks.Count > 0)
            {
                game.bricks.Clear();
                game.displayMsg = "Cleared Grid";

                //If a level was loaded, then mark it, so that when level has been
                //changed and user tries to exit without saving prompt to save level
                if (this.loadedAnExistingLevel)
                {
                    game.levelSaved = false;
                    game.displayMsg = "Cleared Grid";
                    game.unsaved = "Level has Unsaved Changes!";
                }
            }
            else { game.displayMsg = "Grid is Empty"; }
        }

        private void drawBGToolStripMenuItem_Click(object sender, EventArgs e)
        {
            BG_OnOff();
        }

        private void drawGridToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            GridOnOff();
        }

        private void drawBGToolStripMenuItem_Click_1(object sender, EventArgs e)
        {
            BG_OnOff();
        }

        private void drawGridToolStripMenuItem1_Click_1(object sender, EventArgs e)
        {
            GridOnOff();
        }

        private void addBrickToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddBrick_RightMouse();
        }

        private void removeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RemoveBrick_RightClick();
        }

        private void pctSurface_MouseDown(object sender, MouseEventArgs e)
        {
            game.unsaved = "";

            switch (e.Button)
            {
                case MouseButtons.Left:
                    game.displayMsg = "";
                    if (btnAddBrick.Enabled)
                    {
                        game.leftClickLocation = new Vector2(e.X, e.Y);
                        if (chkBx_SwitchAddRemove.Checked)
                        {
                            //use as remove function...
                            RemoveBrick_LeftClick();
                        }
                        else if (!chkBx_SwitchAddRemove.Checked)
                        {
                            //use as add function
                            AddBrick_LeftClick();
                        }
                    }
                    break;
                case MouseButtons.Middle:
                    break;
                case MouseButtons.None:
                    break;
                case MouseButtons.Right:
                    game.displayMsg = "";
                    game.rightClickLocation = new Vector2(e.X, e.Y);
                    break;
                case MouseButtons.XButton1:
                    break;
                case MouseButtons.XButton2:
                    break;
                default:
                    break;
            }
        }
 
       private void chkBx_SwitchAddRemove_CheckedChanged(object sender, EventArgs e)
        {
            if (chkBx_SwitchAddRemove.Checked)
            {
                chkBx_SwitchAddRemove.Text = "Add: OFF | Delete: ON";
            }
            else
            {
                chkBx_SwitchAddRemove.Text = "Add: ON | Delete: OFF";
            }
        }

        private void Editor_Activated(object sender, EventArgs e)
        {
            ActiveForm.Text = "Ice Breaker Level Editor";
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("hello there....");
        }

        private void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
        {
            saveFileDialog1.Filter = "XML files (*.xml)|*.xml|All files (*.*)|*.*";
            saveFileDialog1.FilterIndex = 2;
            saveFileDialog1.RestoreDirectory = true;

            string fileName = saveFileDialog1.FileName.Trim();
            
            #region GENERATE_XML_FILE
            if (game.bricks.Count != 0)
            {
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;
                //Creat new XML file
                XmlWriter writer = XmlWriter.Create(fileName, settings);

                //Write XML
                writer.WriteStartDocument();
                writer.WriteStartElement("XnaContent");

                int count = 1;
                foreach (Brick brick in game.bricks)
                {
                    writer.WriteStartElement("Brick".ToUpper());

                    writer.WriteElementString("Type".ToUpper(), brick.Type.ToString());
                    writer.WriteElementString("Density".ToUpper(), brick.Density.ToString());
                    writer.WriteElementString("HitCount".ToUpper(), brick.HitCount.ToString());
                    writer.WriteElementString("ScoreValue".ToUpper(), brick.ScoreValue.ToString());
                    writer.WriteElementString("Position".ToUpper(), brick.Position.X.ToString() + " " + brick.Position.Y.ToString());
                    writer.WriteElementString("Size".ToUpper(), brick.Size.X.ToString() + " " + brick.Size.Y.ToString());
                    writer.WriteElementString("Center".ToUpper(), brick.Center.X.ToString() + " " + brick.Center.Y.ToString());
                    writer.WriteElementString("Speed".ToUpper(), brick.Speed.X.ToString() + " " + brick.Speed.Y.ToString());
                    writer.WriteElementString("Direction".ToUpper(), brick.Direction.X.ToString() + " " + brick.Direction.Y.ToString());

                    writer.WriteElementString("brick_count".ToUpper(), count.ToString());
                    ++count;

                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
                writer.WriteEndDocument();

                writer.Flush();
                writer.Close();

                //Update state edit to level has been saved
                this.loadedAnExistingLevel = true;
                game.levelSaved = true;

                game.displayMsg = "Level Saved Successfully";
            }
            else
            {
                if (game.bricks.Count == 0)
                {
                    game.displayMsg = "Level is Empty. Add some assets, then Save.";
                    game.unsaved = "";
                }
            }
            #endregion
        }


        #region USER_METHODS
        private Vector2 CalculatePosition(decimal valueX, decimal valueY)
        {
            Vector2 pos = new Vector2();

            pos.X = 100 + (((int)valueX - 1) * brick.Size.X);
            pos.Y = 100 + (((int)valueY - 1) * brick.Size.Y);
            return pos;
        }

        private void LoadFieldsWithData()
        {
            #region LOAD_SORTED_ENUM LIST_INTO_COMBOBOX
            //Load all enum values into list
            List<BrickType> list1 = Enum.GetValues(typeof(BrickType)).Cast<BrickType>().ToList();
            //create and pass list1 -> list2 converting it into string values
            List<string> list2 = new List<string>();
            foreach (BrickType item in list1) { list2.Add(item.ToString()); }
            //SORT the string list..
            list2.Sort();

            //Add Sorted list into ComboBox...
            foreach (string b in list2) { comboBoxType.Items.Add(b); }
            #endregion

            comboBoxDensity.Items.AddRange(System.Enum.GetNames(typeof(BrickDensity)));
        }

        private void LoadBrick_Textures()
        {
            string[] files = Directory.GetFiles(@"C:\Users\Ronald\Documents\Dropbox\C#\LevelEditor\Content\Bricks");
            foreach (string file in files)
            {
                imageListBricks.Images.Add(Image.FromFile(file));
            }
        }

        private void CheckEditMode_Enabled()
        {
            if (comboBoxType.Text != String.Empty && comboBoxDensity.Text != String.Empty)
            {
                btnAddBrick.Enabled = true;
                addBrickToolStripMenuItem.Enabled = true;
                removeToolStripMenuItem.Enabled = true;
                saveToolStripMenuItem.Enabled = true;
            }
            else
            {
                btnAddBrick.Enabled = false;
                addBrickToolStripMenuItem.Enabled = false;
                removeToolStripMenuItem.Enabled = false;
                saveToolStripMenuItem.Enabled = false;
            }
        }

        private void GridOnOff()
        {
            if (game.drawGrid)
            {
                game.drawGrid = false;
                drawGridToolStripMenuItem.Text = "ON Grid";
                drawGridToolStripMenuItem1.Text = "ON Grid";
            }
            else
            {
                game.drawGrid = true;
                drawGridToolStripMenuItem.Text = "OFF Grid";
                drawGridToolStripMenuItem1.Text = "OFF Grid";
            }
        }

        private void BG_OnOff()
        {
            if (game.drawBG)
            {
                game.drawBG = false;
                changeBGToolStripMenuItem1.Text = "ON Background";
                drawBGToolStripMenuItem.Text = "ON Background";
            }
            else
            {
                game.drawBG = true;
                changeBGToolStripMenuItem1.Text = "OFF Background";
                drawBGToolStripMenuItem.Text = "OFF Background";
            }
        }

        private void AddBrickUsingTools()
        {
            game.SwapBrickTexture((BrickType)Enum.Parse(typeof(BrickType), comboBoxType.Text));
            BrickType brickType = (BrickType)Enum.Parse(typeof(BrickType), comboBoxType.Text);

            brick = new Brick(game.brickTexture, brickType, Vector2.Zero);
            brick.Density = (BrickDensity)Enum.Parse(typeof(BrickDensity), comboBoxDensity.Text);
            brick.HitCount = (int)numericUpDown_MaxHits.Value;
            brick.Position = CalculatePosition(numericUpDown_PositionX.Value, numericUpDown_PositionY.Value);
            brick.ScoreValue = (int)numericUpDown_Score.Value;
            textBox_SizeWidthHeight.Text = "X: " + brick.Size.X + " Y: " + brick.Size.Y;
            textBox_CenterXY.Text = "X: " + brick.Center.X + " Y: " + brick.Center.Y;
            textBox_SpeedXY.Text = "X: " + brick.Speed.X + " Y: " + brick.Speed.Y;
            textBox_DirectionXY.Text = "X: " + brick.Direction.X + " Y: " + brick.Direction.Y;

            //level has bee changed...
            game.levelSaved = false;
        }

        private void AddBrick_RightMouse()
        {
            //Right-Click Inside Grid Bounds Check
            if ((game.rightClickLocation.X >= 100 && game.rightClickLocation.X < 700) &&
                (game.rightClickLocation.Y >= 100 && game.rightClickLocation.Y < 400)
                )
            {
                AddBrickUsingTools();
                brick.Position = game.rightClickLocation;

                game.addByRightClick = true;
                game.tempBrick = brick;
                game.displayMsg = "";
            }
            else
            {
                game.displayMsg = "Right Click: Must click inside Grid to focus action.";
            }
        }

        private void AddBrick_LeftClick()
        {
            //Left-Click Check
            if ((game.leftClickLocation.X >= 100 && game.leftClickLocation.X < 700) &&
                (game.leftClickLocation.Y >= 100 && game.leftClickLocation.Y < 400)
                )
            {
                AddBrickUsingTools();
                brick.Position = game.leftClickLocation;

                game.addByLeftClick = true;
                game.tempBrick = brick;
                game.displayMsg = "";
            }
            else
            {
                game.displayMsg = "Left Click: Must click inside Grid to focus action.";
            }
        }

        private void RemoveBrick_RightClick()
        {
            game.displayMsg = "";

            if ((game.rightClickLocation.X >= 100 && game.rightClickLocation.X < 700) &&
                (game.rightClickLocation.Y >= 100 && game.rightClickLocation.Y < 400)
                )
            {
                game.removeByRightClick = true;
            }
            else
            {
                game.clickedOutsideGrid = true;
                game.displayMsg = "Right Click: Must click inside Grid to focus action.";
            }
        }

        private void RemoveBrick_LeftClick()
        {
            game.displayMsg = "";

            if ((game.leftClickLocation.X >= 100 && game.leftClickLocation.X < 700) &&
                (game.leftClickLocation.Y >= 100 && game.leftClickLocation.Y < 400)
                )
            {
                game.removeByLeftClick = true;
                game.displayMsg = "Left Click: Successfully removed....";
            }
            else
            {
                game.clickedOutsideGrid = true;
                game.displayMsg = "Left Click: Must click inside Grid to focus action.";
            }
        }

        #endregion    

        
    }//class
}//namespace